#include "QSpectrumView.h"

#include <assert.h>
#include <limits>
#include <sstream>
#include "QtGui/QPainter.h"
#include "QtGui/QEvent.h"

QSpectrumView::QSpectrumView( QWidget* _parent )
	:	QWidget(_parent)
{
	mPowerLevel = 0.f;
	mDebugText = "debug";
	mDebugText2 = "debug";
	mDebugText3 = "debug";
	setMouseTracking(true);
}

void QSpectrumView::setWaveFormWindow( SampleWindow* waveFormWindow )
{
	mWaveFormWindow = waveFormWindow;
	mWaveFormWindow->registerListener( this );

	sampleWindowChanged( mWaveFormWindow );
}

void QSpectrumView::sampleWindowChanged( SampleWindow* sampleWindow )
{
	updateDST();
	update();
}

void QSpectrumView::mousePressEvent( QMouseEvent* mouseEvent )
{
}

void QSpectrumView::mouseReleaseEvent( QMouseEvent* mouseEvent )
{
}

void QSpectrumView::mouseMoveEvent( QMouseEvent* mouseEvent )
{

	int x = mouseEvent->x();

	std::stringstream stream;
	
	float oneBinWidth = (float)width()/ (float)mDST.size();
	float binNumFloat = ((float)x / oneBinWidth) + 0.5f;
	int binNumber = (int)(binNumFloat);
	
	std::size_t numSamples = mDST.size() * 2;
	float minPartialFreq = (float)sampleRate / (float)numSamples;
	float binFreq = minPartialFreq * binNumber;

	stream << "xv: " << x << " bin#: " << binNumber << " bin hz:" << binFreq;

	mDebugText3 = stream.str().c_str();




	update();


	/*std::size_t numSamples = mWaveFormWindow.getSamples().size();
	const int sampleRate = 8000;
	const float oneSampleDuration = 1.f / sampleRate;
	float maxPartialPeriod =  numSamples * oneSampleDuration;
	float minPartialFreq = 1.f / maxPartialPeriod;
	// or:
	minPartialFreq = (float)sampleRate / (float)numSamples;

	// and
	float minPartialPeriod = 2.f * oneSampleDuration;
	float maxPartialFreq = 1.f / minPartialPeriod;
	// or: 
	maxPartialFreq = (float)sampleRate / 2.f;

	std::stringstream stream;
	stream << "min hz: " << minPartialFreq << " max hz: " << maxPartialFreq << " num bins: " << mDST.size();
	mDebugText2 = stream.str().c_str();*/
}

void QSpectrumView::wheelEvent(QWheelEvent* wheelEvent)
{
}

void QSpectrumView::paintEvent(QPaintEvent* _paintEvent)
{
	QPainter painter(this);
	
	QColor backgroundColor( 180, 180, 180 );
	painter.setBrush(backgroundColor);
	painter.drawRect( 0, 0, width()-1, height()-1 );
	
	painter.setBrush(Qt::NoBrush);
	QColor lineColor( 0, 0, 0 ); 
	painter.setPen(lineColor);
	painter.setFont(QFont("Arial", 10));

	{
		std::size_t numDSTPoints = mDST.size();
		float max = std::numeric_limits<float>::min();
		float min = std::numeric_limits<float>::max();
		for ( std::size_t i=0; i<numDSTPoints; ++i )
		{
			if ( mDST[i]>max )
				max = mDST[i];
			if ( mDST[i]<min )
				min = mDST[i];
		}

		std::stringstream stream;
		stream << "min: " << min << " max: " << max  << " power: " << mPowerLevel;
		mDebugText = stream.str().c_str();
		painter.drawText( 5, 15, mDebugText );
		painter.drawText( 5, 30, mDebugText2 );
		painter.drawText( 5, 45, mDebugText3 );


		float h = (float)height();
		float span = (max-min);
		int yZero =  h - ( abs(min) * h / span);
		painter.drawLine( 0, yZero, width(), yZero );
				
		QPoint lastPoint( 0, yZero );
		QVector<QPoint> pointPairs;
		QVector<QPoint> points;
		for ( std::size_t index=0; index<numDSTPoints; ++index )
		{
			QPoint p1 = lastPoint;
			QPoint p2;
			if ( index>=0 && index<numDSTPoints )
			{
				float dstPoint = mDST[index];
				int x2 = index * width() / numDSTPoints;
				int y2 = yZero - ( dstPoint * h / span);
				p2 = QPoint( x2, y2);
				points.append( p2 );
			}
			pointPairs.append( p1 );
			pointPairs.append( p2 );
			lastPoint = p2;
		}
		pointPairs.append( lastPoint );
		pointPairs.append( QPoint(width(), yZero) );
			
		QColor lineColor( 100,100,100 ); 
		painter.setPen(lineColor);
		painter.drawLines( pointPairs );
		
		QColor pointColor( 30, 30, 30 ); 
		QPen pointPen(pointColor);
		pointPen.setWidth(2);
		painter.setPen(pointPen);
		painter.drawPoints( points.data(), points.count() );
	}
}

void QSpectrumView::updateDST()
{
	mDST.clear();
	if ( mWaveFormWindow )
	{
	


		WaveForm::NormalizedSamples normalizedSamples;
		mWaveFormWindow->getNormalizedSamples( normalizedSamples );
		//WaveForm::calculateDST( normalizedSamples, mDST );
		
// old
/*std::vector<float> sinPart;
std::vector<float> cosPart;
WaveForm::calculateDFTold( normalizedSamples, sinPart, cosPart);

mDST.resize( sinPart.size() );
for ( std::size_t i=0; i<sinPart.size(); ++i )
{
	//mDST[i] = 20.f * log10( 2.f * sqrt( sinPart[i]*sinPart[i] + cosPart[i]*cosPart[i] ) / (float)normalizedSamples.size() );
	mDST[i] = sqrt( sinPart[i]*sinPart[i] + cosPart[i]*cosPart[i] ) / (float)normalizedSamples.size();
}*/


		WaveForm::FFTBins fftBins;
		WaveForm::calculateFFT( normalizedSamples, fftBins );

		mDST.resize( fftBins.size() );
		for ( std::size_t i=0; i<fftBins.size(); ++i )
		{
			mDST[i] = sqrt( fftBins[i].first*fftBins[i].first + fftBins[i].second*fftBins[i].second ) / (float)normalizedSamples.size();
		}

		mPowerLevel = WaveForm::calculatePowerLevel( fftBins );

		std::size_t numSamples = normalizedSamples.size();
		const float oneSampleDuration = 1.f / sampleRate;
		float maxPartialPeriod =  numSamples * oneSampleDuration;
		float minPartialFreq = 1.f / maxPartialPeriod;
		// or:
		minPartialFreq = (float)sampleRate / (float)numSamples;

		// and
		float minPartialPeriod = 2.f * oneSampleDuration;
		float maxPartialFreq = 1.f / minPartialPeriod;
		// or: 
		maxPartialFreq = (float)sampleRate / 2.f;

		std::stringstream stream;
		stream << "min hz: " << minPartialFreq << " max hz: " << maxPartialFreq << " num bins: " << mDST.size();
		mDebugText2 = stream.str().c_str();
	}
}